/** by YPC
*/
#include "xMappingNode.h"
#include "xNodeType.h"
#include "xNodeType_gate.h"
#include "vmLibrary.h"
#include "xParameterPack.h"
#include "all_entries.h"
#include "xInMappingPort.h"
#include "xOutMappingPort.h"

string convert_to_string(xParameter xp);
using namespace std; 
void xNodeType_gate::setupPorts() {

	assert(_parent != NULL);
	if (_xp.type == "wop") {
		_parent->_inports.push_back(new xInMappingPort("wop",_parent));
		_parent->_outports.push_back(new xOutMappingPort("wop", _parent));
	} else if (_xp.type == "varname") {
		_parent->_inports.push_back(new xInMappingPort("varname",_parent));
		_parent->_outports.push_back(new xOutMappingPort("varname", _parent));
	} else if (_xp.type == "tostring*") {
		_parent->_inports.push_back(new xInMappingPort("tostring*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("tostring*", _parent));
	} 	else if (_xp.type == "vm") {
		_parent->_inports.push_back(new xInMappingPort("vm",_parent));
		_parent->_outports.push_back(new xOutMappingPort("vm", _parent));
	} else if (_xp.type == "wops") {
		_parent->_inports.push_back(new xInMappingPort("wops",_parent));
		_parent->_outports.push_back(new xOutMappingPort("wops", _parent));
	} else if (_xp.type == "vms") {
		_parent->_inports.push_back(new xInMappingPort("vms",_parent));
		_parent->_outports.push_back(new xOutMappingPort("vms", _parent));
	} else if (_xp.type == "int*") {
		_parent->_inports.push_back(new xInMappingPort("int*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("int*", _parent));
	} else if (_xp.type == "int") {
		_parent->_inports.push_back(new xInMappingPort("int",_parent));
		_parent->_outports.push_back(new xOutMappingPort("int", _parent));
	} else if (_xp.type == "float") {
		_parent->_inports.push_back(new xInMappingPort("float",_parent));
		_parent->_outports.push_back(new xOutMappingPort("float", _parent));
	} else if (_xp.type == "float*") {
		_parent->_inports.push_back(new xInMappingPort("float*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("float*", _parent));
	} else if (_xp.type == "double") {
		_parent->_inports.push_back(new xInMappingPort("double",_parent));
		_parent->_outports.push_back(new xOutMappingPort("double", _parent));
	} else if (_xp.type == "double*") {
		_parent->_inports.push_back(new xInMappingPort("double*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("double*", _parent));
	} else if (_xp.type == "char") {
		_parent->_inports.push_back(new xInMappingPort("char",_parent));
		_parent->_outports.push_back(new xOutMappingPort("char", _parent));
	} else if (_xp.type == "char*") {
		_parent->_inports.push_back(new xInMappingPort("char*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("char*", _parent));
	} else if (_xp.type == "bool") {
		_parent->_inports.push_back(new xInMappingPort("bool",_parent));
		_parent->_outports.push_back(new xOutMappingPort("bool", _parent));
	} else if (_xp.type == "bool*") {
		_parent->_inports.push_back(new xInMappingPort("bool*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("bool*", _parent));
	} else if (_xp.type == "string") {
		_parent->_inports.push_back(new xInMappingPort("string",_parent));
		_parent->_outports.push_back(new xOutMappingPort("string", _parent));
	} else if (_xp.type == "string*") {
		_parent->_inports.push_back(new xInMappingPort("string*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("string*", _parent));
	} else if (_xp.type == "Quaternion*") {
		_parent->_inports.push_back(new xInMappingPort("Quaternion*",_parent));
		_parent->_outports.push_back(new xOutMappingPort("Quaternion*", _parent));
	} else {
		assert(false); // what other type a pipe mapping node can be?
	}
	
}
void xNodeType_gate::setName(string name) {
	xMappingNode *node = this->getParent();
	xInMappingPort *inp = node->getInPort(0);
	inp->setName(name);
	xOutMappingPort* omp = node->getOutPort(0);
	omp->setName(name);
}
void xNodeType_gate::setClass( MNClass classtype ) {
	xMappingNode *node = this->getParent();
	xInMappingPort *inp = node->getInPort(0);
	inp->setClass(classtype);
	xOutMappingPort* omp = node->getOutPort(0);
	omp->setClass(classtype);
}

void xNodeType_gate::setCategory( MNCategory category )
{
	xMappingNode *node = this->getParent();
	xInMappingPort *inp = node->getInPort(0);
	inp->setCategory(category);
	xOutMappingPort* omp = node->getOutPort(0);
	omp->setCategory(category);
}

int xNodeType_gate::getClass() {
	xMappingNode *node = this->getParent();
	xInMappingPort *inp = node->getInPort(0);
	return inp->getClass();
}
void xNodeType_gate::setDefaultValue(string defaultvalue) {
	xMappingNode *node = this->getParent();
	xInMappingPort *inp = node->getInPort(0);
	inp->setDefaultValue(defaultvalue);
	//xOutMappingPort* omp = node->getOutPort(0);
	//omp->setDefaultValue(defaultvalue);
}
string xNodeType_gate::getDefaultValue() {
	xMappingNode *node = this->getParent();
	xInMappingPort *inp = node->getInPort(0);
	return inp->getDefaultValue();
}

void xNodeType_gate::createMappedObject() {
	xMappingNode *node = this->getParent();
	assert(node->getInportSize() == 1);
	xInMappingPort *inp = node->getInPort(0);
	_xp = inp->toXParameter();
}
bool xNodeType_gate::update() {
	xMappingNode *node = this->getParent();
	assert(node->getInportSize() == 1);
	xInMappingPort *inp = node->getInPort(0);
	_xp = inp->toXParameter();
	return true ;

}
xParameter xNodeType_gate::toXParameter(string type, xOutMappingPort * linked_op) {
	// when this node is connected to a parent P at higher level
	// P can ask for its xParameter
	xMappingNode *node = this->getParent();
	assert(node->getOutportSize() == 1);
	xOutMappingPort *outp = node->getOutPort(0);
	assert(linked_op == outp);
	
	if (_xp.type == "wop") {
		// this is a special case for a gate wop
		// the gate only store the wop, but cannot handle to type like "tostring*"
		// so we pass this request to its wop_nodetype
		assert(_xp.wop_nodetype != NULL);
		return _xp.wop_nodetype->toXParameter(type, linked_op);
	}
	return _xp ;
	
}

string xNodeType_gate::toMDString(MDSType type) {

	// 目前還沒有 gate 要被放進 parameterized block 的例子
	if ( type == xNodeType::ParameterizedMDSFormat)
		assert(false);

	ostringstream MDSstr ;
	xInMappingPort *inp = _parent->getInPort(0);
	// a gate inport's name can be reset in mapping dialog
	// so we use the last paremeter to store the new name
	MDSstr <<  "node " << _parent->getSerialNo() << " gate " << _xp.type << " " 
		   << inp->getName()  << " "   << CLASS_to_string(inp->getClass())   << " " 
		   << inp->getDefaultValue() << " " <<  CATEGORY_to_string(inp->getCategory()) << endl ; 
	assert(inp->getDefaultValue() != "");
	return MDSstr.str();

}
int  xNodeType_gate::parseMDString(vector<string>& tokens, int start_index) {
	int i = start_index ;
	assert(tokens[i] == "node");
	string serialno = tokens[i+1] ;
	assert(tokens[i+2] == "gate");
	string nodetype = tokens[i+3] ; // nodetypes are "wop" "vm" "vmcollector"
	string gatename = tokens[i+4] ; // parameter 1 of an wop is vartype()
	string gateclass = tokens[i+5] ; // parameter 2 of an wop is its shortname. 
	string gatedefaultvalue = tokens[i+6] ;
	string gatecategory = tokens[i+7];
	
	this->setName(gatename);
	if (string_to_CLASS(gateclass) == -1) 
		assert(false);
	this->setClass(string_to_CLASS(gateclass));
	this->setDefaultValue(gatedefaultvalue);
	if ( gatecategory == "NAME") {
		this->setCategory(CATEGORY_NAME);
	} else if ( gatecategory == "POSITION" ) {
		this->setCategory(CATEGORY_POSITION);
	} else if ( gatecategory == "SIZE" ) {
		this->setCategory(CATEGORY_SIZE);
	} else if ( gatecategory == "COLOR" ) {
		this->setCategory(CATEGORY_COLOR);
	} else if ( gatecategory == "ROTATION" ) {
		this->setCategory(CATEGORY_ROTATION);
	} else if ( gatecategory == "SCALE" ) {
		this->setCategory(CATEGORY_SCALE);
	} else if ( gatecategory == "OTHER" ) {
		this->setCategory(CATEGORY_OTHER);
	} else assert(false);
	return 8 ;
}

string convert_to_string(xParameter xp) {
	ostringstream buf;
	if (xp.type == "wop") {
		
	} else if (xp.type == "vm") {
	
	} else if (xp.type == "wops") {
		
	} else if (xp.type == "vms") {
	
	} else if (xp.type == "int*") {
		buf << (*xp.val_int_ptr);
		return buf.str();
	} else if (xp.type == "int") {
		buf << (xp.val_int);
		return buf.str();
	} else if (xp.type == "float") {
		buf << (xp.val_float);
		return buf.str();
	} else if (xp.type == "float*") {
		buf << (*xp.val_float_ptr);
		return buf.str();	
	} else if (xp.type == "double") {
		buf << (xp.val_double);
		return buf.str();
	} else if (xp.type == "double*") {
		buf << (*xp.val_double_ptr);
		return buf.str();	
	} else if (xp.type == "char") {
		buf << (xp.val_char);
		return buf.str();
	} else if (xp.type == "char*") {
		buf << (*xp.val_char_ptr);
		return buf.str();
	} else if (xp.type == "bool") {
		buf << (xp.val_bool);
		return buf.str();
	} else if (xp.type == "bool*") {
		buf << (*xp.val_bool_ptr);
		return buf.str();
	}else if (xp.type == "string") {
		buf << (xp.val_string);
		return buf.str();
	} else if (xp.type == "string*") {
		buf << (*xp.val_string_ptr);
		return buf.str();
	}  
	assert(false); // what other type a pipe mapping node can be?
	return "" ;
}
string xNodeType_gate::valid_pair[][2] = { // the left is the woptype of this node, right is the link that connects to
"dontcare", "tostring*",
"wop", "varname"
};

bool xNodeType_gate::verify_rhs_link(xOutMappingPort *left, xInMappingPort *right, xNodeType* rightnode) {

	string gatetype = _xp.type ;
	if (gatetype == right->getType()) return true ;
	return check_valid_pair(valid_pair, sizeof(valid_pair)/(sizeof(string)*2),
							gatetype, right->getType());
}
bool xNodeType_gate::verify_lhs_link(xOutMappingPort *left, xNodeType* leftnode, xInMappingPort *right) {
	return true ; // no node should connect from the left hand side
}


